package io.gitee.chearnee.fw.log.sql.parse;

import cn.hutool.core.text.CharSequenceUtil;
import io.gitee.chearnee.fw.log.sql.model.entity.SqlColumn;
import io.gitee.chearnee.fw.log.sql.model.entity.SqlEntity;
import io.gitee.chearnee.fw.log.sql.parse.jsqlparser.IParseStatement;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.update.UpdateSet;
import org.apache.ibatis.mapping.SqlCommandType;

import java.util.ArrayList;
import java.util.List;

/**
 * @author cn
 * @version 1.0
 * @description
 * @date 2023/7/4 14:56
 */
@Slf4j
public class SqlParserUtil implements IParser, IParseStatement {
    public SqlEntity parse(String completeSql) {
        SqlEntity sqlEntity = null;
        if (CharSequenceUtil.isEmpty(completeSql)) {
            return sqlEntity;
        }
        Statement parseSql = null;
        try {
            parseSql = CCJSqlParserUtil.parse(completeSql);
        } catch (JSQLParserException ignored) {
        }
        if (parseSql == null) {
            return sqlEntity;
        }
        if (parseSql instanceof Select) {
            sqlEntity = parseStatementImpl((Select) parseSql);
        }
        if (parseSql instanceof Update) {
            sqlEntity = parseStatementImpl((Update) parseSql);
        }
        if (parseSql instanceof Insert) {
            sqlEntity = parseStatementImpl((Insert) parseSql);
        }
        if (parseSql instanceof Delete) {
            sqlEntity = parseStatementImpl((Delete) parseSql);
        }
        return sqlEntity;
    }

    public SqlEntity parseStatementImpl(Select parseSql) {
        SelectBody selectBody = parseSql.getSelectBody();
        SqlEntity sqlEntity = new SqlEntity(SqlCommandType.SELECT, parseSql.toString());
        if (selectBody instanceof PlainSelect plainSelect) {
            sqlEntity.setTable(plainSelect.getFromItem().toString());
            List<SelectItem> selectItems = plainSelect.getSelectItems();
            for (SelectItem selectItem : selectItems) {
                sqlEntity.getColumnList().add(SqlColumn.builder().column(selectItem.toString())
                        .original(selectItem.toString()).build());
            }
            sqlEntity.setWhere(plainSelect.getWhere().toString());
        }
        return sqlEntity;
    }

    public SqlEntity parseStatementImpl(Update parseSql) {
        SqlEntity sqlEntity = new SqlEntity(SqlCommandType.UPDATE, parseSql.toString());
        sqlEntity.setTable(parseSql.getTable().toString());
        sqlEntity.setWhere(parseSql.getWhere().toString());
        ArrayList<UpdateSet> updateSets = parseSql.getUpdateSets();
        for (UpdateSet updateSet : updateSets) {
            ArrayList<Expression> expressions = updateSet.getExpressions();
            ArrayList<Column> column = updateSet.getColumns();
            for (int i = 0; i < column.size(); i++) {
                SqlColumn.SqlColumnBuilder builder = SqlColumn.builder();
                builder.column(column.get(i).toString());
                builder.value(expressions.get(i).toString());
                SqlColumn build = builder.build();
                build.setOriginal(build.getColumn() + "=" + build.getValue());
                sqlEntity.getColumnList().add(build);
            }
        }
        return sqlEntity;
    }

    public SqlEntity parseStatementImpl(Insert parseSql) {
        SqlEntity sqlEntity = new SqlEntity(SqlCommandType.INSERT, parseSql.toString());
        sqlEntity.setTable(parseSql.getTable().toString());
        List<Column> columns = parseSql.getColumns();
        ItemsList itemsList = parseSql.getItemsList();
        List<Expression> itemsValue = null;
        if (itemsList instanceof ExpressionList items) {
            itemsValue = items.getExpressions();
        }
        for (int i = 0; i < columns.size(); i++) {
            Column column = columns.get(i);
            SqlColumn.SqlColumnBuilder builder = SqlColumn.builder();
            builder.column(column.toString());
            if (itemsValue != null) {
                Expression expression = itemsValue.get(i);
                builder.value(expression.toString());
            }
            SqlColumn build = builder.build();
            build.setOriginal(build.getColumn() + "=" + build.getValue());
            sqlEntity.getColumnList().add(build);
        }
        return sqlEntity;
    }

    public SqlEntity parseStatementImpl(Delete parseSql) {
        SqlEntity sqlEntity = new SqlEntity(SqlCommandType.DELETE, parseSql.toString());
        return sqlEntity;
    }

    @Override
    public Object parserToObj(String completeSql) {
        return parse(completeSql);
    }
}
